package cn.sc.summer.security.config;

import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.StrUtil;
import cn.sc.summer.constant.project.ProjectConstant;
import cn.sc.summer.constant.token.TokenConstant;
import cn.sc.summer.constant.util.MatchUtil;
import cn.sc.summer.redis.util.RouteUtil;
import cn.sc.summer.token.constant.APIConstant;
import cn.sc.summer.token.constant.LoginAPIConstant;
import cn.sc.summer.token.encrypt.TokenUtil;
import cn.sc.summer.token.enums.RequestTypeEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authorization.AuthorizationDecision;
import org.springframework.security.authorization.AuthorizationManager;
import org.springframework.security.web.access.intercept.RequestAuthorizationContext;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.util.Optional;
import java.util.function.Supplier;

/**
 * 类名：校验用户访问资源是否合法且有权限
 *
 * @author a-xin
 * @date 2024/9/18 17:31
 */
@Slf4j
@Component
public class AuthorizationManagerX implements AuthorizationManager<RequestAuthorizationContext> {

    private static final String[] IGNORE_URL = {
            LoginAPIConstant.LOGIN_API,
            LoginAPIConstant.APP_LOGIN,
            LoginAPIConstant.SMS_LOGIN
    };

    /**
     * Determines if access is granted for a specific authentication and object.
     *
     * @return an {@link AuthorizationDecision} or null if no decision could be made
     */
    @Override
    public AuthorizationDecision check(Supplier authentication, RequestAuthorizationContext requestAuthorizationContext) {
        HttpServletRequest request = requestAuthorizationContext.getRequest();

        String requestURI = request.getRequestURI();
        String rawPath = RouteUtil.getRawPath(ProjectConstant.SERVER_NAME, requestURI);
        if (CharSequenceUtil.isBlank(rawPath)) {
            return new AuthorizationDecision(false);
        }
        log.info("-> resource path : {}", rawPath);
        if (MatchUtil.anyMatchValue(rawPath, APIConstant.SWAGGER_SOURCE)
                || MatchUtil.anyMatchValue(rawPath, IGNORE_URL)) {
            return new AuthorizationDecision(true);
        }

        String apiKey = request.getHeader(TokenConstant.API_KEY_REQUEST_HEADER);
        String requestType = request.getHeader(TokenConstant.REQUEST_TYPE);

        if (StrUtil.isBlank(apiKey) || StrUtil.isBlank(requestType)) {
            return new AuthorizationDecision(false);
        }

        Optional<RequestTypeEnum> byType = Optional.ofNullable(RequestTypeEnum.getByType(requestType));
        if (!byType.isPresent()) {
            return new AuthorizationDecision(false);
        }

        Boolean tokenCheck = TokenUtil.analysisApiEncryptKey(apiKey, byType.get());
        if (!tokenCheck) {
            return new AuthorizationDecision(false);
        }

        return new AuthorizationDecision(true);
    }

}
